package cn.congine.wizarpos.mall.service.impl;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.congine.wizarpos.mall.exception.MangoException;
import cn.congine.wizarpos.mall.model.open.AccessTokenInput;
import cn.congine.wizarpos.mall.model.open.AccessTokenOutput;
import cn.congine.wizarpos.mall.model.open.CommonResultOutput;
import cn.congine.wizarpos.mall.model.open.GetOrderNoInput;
import cn.congine.wizarpos.mall.model.open.GetOrderNoOutput;
import cn.congine.wizarpos.mall.model.open.GetWxOrderNoInput;
import cn.congine.wizarpos.mall.model.open.GetWxOrderNoOutput;
import cn.congine.wizarpos.mall.model.open.RechargeMarketInfo;
import cn.congine.wizarpos.mall.model.open.TicketInfoPayUse;
import cn.congine.wizarpos.mall.model.open.TicketPayUseInput;
import cn.congine.wizarpos.mall.model.open.TicketPayUseOutput;
import cn.congine.wizarpos.mall.utils.SysConstants;
import cn.congine.wizarpos.mall.utils.WxSignUtil;

@Service("wposHttpClient")
public class WPosHttpClient {
	private final Log log = LogFactory.getLog(getClass());
	private static final int DEFAULT_TIMEOUT = 10000;
	private static final String WPCharset = "UTF-8";
	private static final String JsonContentType = "application/json";
//	private CloseableHttpClient httpClient;
	private static String memberURL = "";
	private static String cashierURL = "";
	private static String openURL = "";
	@Resource(name = "messageSource")
	private MessageSource messageSource;
	
	@Autowired
	private WizarposOpenRestClient wizarposOpenRestClient;

	@PostConstruct
	public void initialize() {
		memberURL = messageSource.getMessage(SysConstants.POS_SERVICE_MEMBER,
				null, Locale.ENGLISH);
		cashierURL = messageSource.getMessage(SysConstants.POS_SERVICE_CASHIER,
				null, Locale.ENGLISH);
		openURL = messageSource.getMessage(SysConstants.POS_SERVICE_OPEN, null,
				Locale.ENGLISH);
		log.debug("memberURL = " + memberURL);
		log.debug("cashierURL = " + cashierURL);
		log.debug("openURL = " + openURL);
	}

	/**
	 * web service 请求得到交易流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	public String getTranLogId(String mid) throws Exception {
		JSONObject param = new JSONObject();
		param.put("mid", mid);
		;
		JSONObject json = new JSONObject();
		json.put("service_code", "1010");
		json.put("param", param);
		return (String) postMember(json).getJSONObject("result").get(
				"tranLogId");
	}

	/**
	 * 请求得到微信交易订单流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	public String getWxOrderNo(String mid) {
		GetWxOrderNoInput input = new GetWxOrderNoInput();
		input.setMid(mid);
		GetWxOrderNoOutput output = (GetWxOrderNoOutput) wizarposOpenRestClient.post(input,"/wxshop/getWxOrderNo",GetWxOrderNoOutput.class);
		if (output == null) {
			log.error("请求开放平台取微信交易订单流水号接口失败");
			return null;
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode()) && output.getResult() != null) {
			return output.getResult().getOrderNo();
		} else {
			log.error("code：" + output.getCode());
			log.error("message：" + output.getMessage());
			log.debug("mid="+mid);
			return null;
		}
	}

	/**
	 * 请求得到线上交易订单流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	public String getWxOrderNo(String mid, String type) {
		GetWxOrderNoInput input = new GetWxOrderNoInput();
		input.setMid(mid);
		input.setEnvType(type);
		GetWxOrderNoOutput output = (GetWxOrderNoOutput) wizarposOpenRestClient.post(input,"/wxshop/getWxOrderNo",GetWxOrderNoOutput.class);
		if (output == null) {
			log.error("请求开放平台取微信交易订单流水号接口失败");
			return null;
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode()) && output.getResult() != null) {
			return output.getResult().getOrderNo();
		} else {
			log.error("code：" + output.getCode());
			log.error("message：" + output.getMessage());
			log.debug("mid="+mid);
			return null;
		}
	}
	
	/**
	 * 请求得到微信交易订单流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	private GetOrderNoOutput.Result getOrderNo(String mid, String shopMid,
			String cardId, Integer amount, Integer extraAmount,
			Integer inputAmount, String ticketInfoIds) {
		GetOrderNoInput input = new GetOrderNoInput();
		input.setMid(mid);
		input.setShopMid(shopMid);
		input.setCardId(cardId);
		input.setAmount(amount);
		input.setExtraAmount(extraAmount);
		input.setInputAmount(inputAmount);
		if (!StringUtils.isEmpty(ticketInfoIds)) {
			input.setTicketInfoIds(Arrays.asList(ticketInfoIds.split(",")));
		}
		GetOrderNoOutput output = (GetOrderNoOutput) wizarposOpenRestClient.post(input,"/wxshop/getOrderNo",GetOrderNoOutput.class);
		if (output == null) {
			log.error("请求开放平台取微信交易订单流水号接口失败");
			return null;
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode()) && output.getResult() != null) {
			return output.getResult();
		} else {
			log.error("code：" + output.getCode());
			log.error("message：" + output.getMessage());
			log.debug("mid="+mid);
			return null;
		}
	}
	
	/**
	 * 请求得到微信交易订单流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	public GetOrderNoOutput.Result getOrderNo(String mid, String shopMid,
			String envType, String cardId, Integer amount, Integer extraAmount,
			Integer inputAmount, String ticketInfoIds, String marketActivity) {
		GetOrderNoInput input = new GetOrderNoInput();
		input.setMid(mid);
		input.setShopMid(shopMid);
		input.setEnvType(envType);
		input.setCardId(cardId);
		input.setAmount(amount);
		input.setExtraAmount(extraAmount);
		input.setInputAmount(inputAmount);
		if (!StringUtils.isEmpty(ticketInfoIds)) {
			input.setTicketInfoIds(Arrays.asList(ticketInfoIds.split(",")));
		}
		input.setMarketActivity(marketActivity);
		GetOrderNoOutput output = (GetOrderNoOutput) wizarposOpenRestClient.post(input,"/wxshop/getOrderNo",GetOrderNoOutput.class);
		if (output == null) {
			log.error("请求开放平台取微信交易订单流水号接口失败");
			return null;
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode()) && output.getResult() != null) {
			return output.getResult();
		} else {
			log.error("code：" + output.getCode());
			log.error("message：" + output.getMessage());
			log.debug("mid="+mid);
			return null;
		}
	}
	
	/**
	 * web service 请求得到微信交易订单流水号
	 * 
	 * @param mid
	 * @return
	 * @throws MangoException
	 */
	public String getOrderId(String mid) throws Exception {
		JSONObject param = new JSONObject();
		param.put("mid", mid);
		;
		JSONObject json = new JSONObject();
		json.put("service_code", "1012");
		json.put("param", param);
		return (String) postMember(json).getJSONObject("result").get(
				"wxOrderId");
	}

	/**
	 * 取会员券流水号,T打头
	 * 
	 * @param mid
	 * @return
	 */
	public String getTicketInfoNO(String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		JSONObject json = new JSONObject();
		json.put("service_code", "1011");
		json.put("param", param);
		String ticketInfoId = null;
		try {
			JSONObject resJson = postMember(json);
			ticketInfoId = resJson.getJSONObject("result").getString(
					"ticketInfoId");
		} catch (Exception e) {
			throw new RuntimeException("生成序列号错误");
		}
		if (ticketInfoId == null) {
			throw new RuntimeException("生成序列号错误");
		}
		return ticketInfoId;
	}

	// 请求会员易 pos service
	public JSONObject postMember(JSONObject json) throws Exception {
		return post(memberURL, json);
	}

	// 请求收银易 pos service
	public JSONObject postCashier(JSONObject json) throws Exception {
		return post(cashierURL, json);
	}

	// 请求开放平台接口
	public JSONObject postOpen(String method, JSONObject json) throws Exception {
		return post(openURL + method, json);
	}

	public JSONObject post(String url, JSONObject json) throws Exception {
		System.out.print("-------WPosHttpClient.post()-------url = " + url);
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(DEFAULT_TIMEOUT)
				.setConnectTimeout(DEFAULT_TIMEOUT)
				.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY).build();
		
		CloseableHttpClient  httpClient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig).build();

		HttpPost httpPost = new HttpPost(url);
		// TODO 请求报文需要签名
		/* json.put("signature", ""); */

		log.debug("request json:" + json.toJSONString());
		CloseableHttpResponse response = null;
		try {
			StringEntity postEntity = new StringEntity(json.toJSONString(),
					ContentType.create(JsonContentType, WPCharset));
			httpPost.setEntity(postEntity);
			for (int i = 0; i < 3; i++) {
				response = httpClient.execute(httpPost);
				if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
					break;
				}
			}
			log.debug("StatusCode:" + response.getStatusLine().getStatusCode());
			if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_OK) {
				System.out.print(response.getEntity().getContent());
				throw new Exception("Access failed");
			}
			byte[] result = EntityUtils.toByteArray(response.getEntity());
			return parseResult(result);
		} catch (UnknownHostException he) {
			
			response = httpClient.execute(httpPost);
			
			log.debug("StatusCode:" + response.getStatusLine().getStatusCode());
			if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_OK) {
				throw new Exception("Access failed");
			}
			byte[] result = EntityUtils.toByteArray(response.getEntity());
			return parseResult(result);
		} catch (Exception e) {
			log.error("调用服务器失败!" + e);
			throw new Exception("调用服务器失败!");
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					log.error(e);
				}
			}
		}
	}

	public JSONObject get(String url) throws Exception {
		System.out.print("-------WPosHttpClient.get()-------url = " + url);
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(DEFAULT_TIMEOUT)
				.setConnectTimeout(DEFAULT_TIMEOUT)
				.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY).build();
		
		CloseableHttpClient  httpClient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig).build();
		
		HttpGet httpGet = new HttpGet(url);

		HttpResponse response = null;
		try {
			for (int i = 0; i < 3; i++) { //考虑网络问题，最多请求3此
				response = httpClient.execute(httpGet);
				if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
					break;
				}
			}
			log.debug("StatusCode:" + response.getStatusLine().getStatusCode());
			if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_OK) {
				System.out.print(response.getEntity().getContent());
				throw new Exception("Access failed");
			}
			byte[] result = EntityUtils.toByteArray(response.getEntity());
			return parseResult(result);
		} catch (Exception e) {
			log.error("微信接口服务器失败!" + e);
			throw new Exception("Access failed");
		}
	}

	private JSONObject parseResult(byte[] response) throws Exception {
		JSONObject json = null;
		if ((response == null) || (response.length == 0)) {
			throw new Exception("无响应报文");
		}
		String content = toString(response, WPCharset);
		log.debug("response json:" + content);
		json = JSONObject.parseObject(content);
		// TODO 响应报文需要验证签名
		return json;
	}

	private String toString(byte[] content, String charsetName)
			throws Exception {
		try {
			return new String(content, charsetName);
		} catch (UnsupportedEncodingException e) {
			throw new Exception("Unsupported encoding");
		}
	}

	/**
	 * 取预约单流水号
	 * 
	 * @param mid
	 * @return
	 */
	public String getCarterOrderNo(String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		JSONObject json = new JSONObject();
		json.put("service_code", "1002");
		json.put("param", param);
		String carterOrderNo = null;
		try {
			JSONObject resJson = postCashier(json);
			carterOrderNo = resJson.getJSONObject("result").getString(
					"carterOrderNo");
		} catch (Exception e) {
			throw new RuntimeException("取预约单流水号错误");
		}
		if (carterOrderNo == null) {
			throw new RuntimeException("取预约单流水号错误");
		}

		return carterOrderNo;
	}

	/**
	 * 查询微信会员卡是否存在
	 * 
	 * @param mid
	 * @return
	 */
	public JSONObject getMerchantCardByOpenId(String openId, String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("openId", openId);// mid慧商户号
		param.put("extUserId", openId);//外部系统唯一识别号		
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1002");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			// 调用会员易对外接口查询是否存在微信会员卡
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("查询微信会员卡是否存在出错");
		}

		return resJson;
	}
	

	/**
	 * 查询会员卡券信息
	 * 
	 * @param mid
	 * @return
	 */
	public JSONObject getMemberTicketInfo(String openId, String mid, String cardId) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("openId", openId);// 
		param.put("cardId", cardId);//会员卡ID
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1003");
		json.put("param", param);		
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("查询会员卡券信息出错");
		}

		return resJson;
	}
	
	/**
	 * 查询会员卡券信息
	 * 
	 * @param mid
	 * @return
	 */
	public JSONObject getQRcodeTokenId(String openId, String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("openId", openId);// 
		param.put("extUserId", openId);//外部系统唯一识别号
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1005");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("查询会员卡券信息出错");
		}

		return resJson;
	}

	/**
	 * 营销活动扣减金额（member-server 1053）
	 * 返回 map，reducAmount 实际需要支付金额
	 * 
	 * @param mid
	 * @param cardNo
	 * @param payMethod
	 * @param rechargeOn
	 * @param payAmount
	 * @return
	 */
	public Map<String, Object> payBeforeByMarketingRule(String mid, String cardNo, String payMethod, String rechargeOn, Integer payAmount) {
		JSONObject param = new JSONObject();
		param.put("mid", mid); // 慧商户号
		param.put("cardNo", cardNo); // 会员卡号
		param.put("payMethod", payMethod); //1 现金支付,2 会员卡支付,3 微信支付, 4 支付宝支付,5 银行卡支付,6 百度钱包支付 7QQ钱包支付
		param.put("rechargeOn", rechargeOn); // 是否充值 1是0否
		param.put("payAmount", payAmount); // 支付金额
		
		JSONObject json = new JSONObject();
		json.put("param", param);
		json.put("service_code", "1053");
		
		JSONObject resJson = null;
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		}
		if (resJson == null || !resJson.containsKey("code") || !"0".equals(resJson.getString("code"))) {
			return null;
		}
		Map<String, Object> result = new HashMap<String, Object>();
		Integer reducAmount = resJson.getJSONObject("result").getInteger("reducAmount");
		
		result.put("reducAmount", reducAmount);
		
		return result;
	}
	
	/**
	 * 外卖退单
	 * 
	 * @param orderId
	 * @return
	 */
	public JSONObject  waimaiCancel(String mid, String orderId) {
		JSONObject param = new JSONObject();
		param.put("orderId", orderId);// 销售单主键
		param.put("mid", mid);// mid
		JSONObject json = new JSONObject();
		json.put("service_code", "1049");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("外卖退单失败");
		}

		return resJson;
	}
	
	/**
	 * 发送短信验证码
	 * 
	 * @param mid 慧商户号
	 * @param phone 手机号
	 * @return
	 */
	public JSONObject  sendVerificationCode(String mid, String phone) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("bizTel", phone);// 手机号
		param.put("applyType", "1");//
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1042");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("发送短信验证码失败");
		}

		return resJson;
	}

	/**
	 * 发送短信验证码
	 * type：1 会员卡注册    5 密码修改 
	 * 
	 * @param mid 慧商户号
	 * @param phone 手机号
	 * @param cardNo 会员卡卡号（密码修改时用）
	 * @param type 1 会员卡注册    5 密码修改 
	 * @return
	 */
	public JSONObject  sendVcode(String mid, String phone, String cardNo, String type) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("bizTel", phone);// 手机号
		param.put("cardNo", cardNo);// 手机号
		param.put("minute", 3);// 手机号
		param.put("applyType", type); // 类型：1 会员卡注册    5 密码修改 
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1051");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("发送短信验证码失败");
		}

		return resJson;
	}

	/**
	 * 获取充值营销活动（member-server 1059）
	 * 
	 * @param mid 慧商户号
	 * @return
	 */
	public Map<String, Object>  getRechargeMarketActivity(String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1059");
		json.put("param", param);
		
		JSONObject resJson = new JSONObject();
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("发送短信验证码失败");
		}

		if (resJson == null || !resJson.containsKey("code") || !"0".equals(resJson.getString("code"))) {
			return null;
		}
		Map<String, Object> result = new HashMap<String, Object>();
		JSONArray marketInfos = resJson.getJSONObject("result").getJSONArray("marketInfo");
//		JSONArray reMarketInfos = new JSONArray();
		List<RechargeMarketInfo> rechargeMarketInfos = new ArrayList<RechargeMarketInfo>(); 
		if (marketInfos != null && !marketInfos.isEmpty()) {
			for (Object o : marketInfos) {
				JSONObject marketInfo = (JSONObject) o;
//				JSONObject reMarketInfo = (JSONObject) o;
				RechargeMarketInfo rechargeMarketInfo = new RechargeMarketInfo();
				Integer money = marketInfo.getInteger("money");
				Integer points = marketInfo.getInteger("points");
				Integer recharge = marketInfo.getInteger("recharge");
				String showMoney = String.valueOf(money / 100);
				String showRecharge = String.valueOf(recharge / 100);
				String ticketName = marketInfo.getString("ticketName");
				
				rechargeMarketInfo.setMoney(money);
				rechargeMarketInfo.setShowMoney(showMoney);
				rechargeMarketInfo.setRecharge(recharge);
				rechargeMarketInfo.setShowRecharge(showRecharge);
				rechargeMarketInfo.setPoints(points);
				rechargeMarketInfo.setTicketName(ticketName);
				rechargeMarketInfos.add(rechargeMarketInfo);
				
//				reMarketInfo.put("money", money);
//				reMarketInfo.put("showMoney", showMoney);
//				reMarketInfo.put("points", points);
//				reMarketInfo.put("recharge", recharge);
//				reMarketInfo.put("showRecharge", showRecharge);
//				reMarketInfo.put("ticketName", ticketName);
//				reMarketInfos.add(reMarketInfo);
				
			}
		}
		
		result.put("rechargeMarketInfos", rechargeMarketInfos);
//		result.put("reMarketInfos", reMarketInfos.toJSONString());
		
		return result;
	}
	
	/**
	 * 快速注册微信会员卡
	 * 
	 * @param mid
	 * @return
	 */
	private JSONObject registerVipCard(String openId, String mid, String name, String phone) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("openId", openId);// mid慧商户号
		param.put("username", name);
		param.put("mobileNo", phone);
		param.put("extUserId", openId);//外部系统唯一识别号
		param.put("extType", "WX");//外部系统类型(WX 微信公众号, ZFB 支付宝服务窗,QQ QQ登陆,SINAWB 新浪微博...)
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1001");
		json.put("param", param);		
		
		JSONObject resJson = new JSONObject();
		try {
			// 调用会员易对外接口查询是否存在微信会员卡
			resJson = postMember(json);

		} catch (Exception e) {
			throw new RuntimeException("注册会员卡失败!");
		}

		return resJson;
	}

	/**
	 * 实体会员卡绑定微信会员卡
	 * 
	 * @param mid
	 *            慧商户号
	 * @param cardNo
	 *            实体会员卡号
	 * @param bindNo
	 *            微信会员卡号
	 * @return
	 * @throws Exception
	 */
	public void bindMemberCard(String mid, String cardNo, String bindNo)
			throws Exception {// 1020 实体会员卡绑定微信会员卡
		JSONObject param = new JSONObject();
		param.put("mid", mid);// 慧商户号
		param.put("cardNo", cardNo);// 实体会员卡号
		param.put("bindNo", bindNo);// 微信会员卡号

		JSONObject json = new JSONObject();
		json.put("param", param);
		json.put("service_code", "1020");

		postMember(json);
	}
	
	/**
	 * 会员消费 1034,按规则赠送积分、券
	 * 
	 * @param mid
	 * @param cardNo
	 * @param amount
	 * @throws Exception
	 */
	public JSONObject transactByRule(String mid, String openId, String cardNo, int payAmount, String wxOrderId, String payType, String cardId)
			throws Exception { 
		JSONObject param = new JSONObject();
		param.put("mid", mid); // 慧商户号
		param.put("openId", openId); // openId
		param.put("wxOrderId", wxOrderId); // 微信订单ID
		param.put("cardNo", cardNo); // 会员卡号
		param.put("payAmount", payAmount); // 交易金额(整型 分为单位)
		param.put("payType", payType); // 1 货到付款 2 微信支付送货上门 3 微信支付到店提货 4 会员卡支付送货上门 5 会员卡支付到店提货
		param.put("cardId", cardId);//会员卡ID
		
		JSONObject json = new JSONObject();
		json.put("param", param);
		json.put("service_code", "1034");

		JSONObject resJson = null;
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		}
		
		return resJson;
	}
	
	/**
	 * 收款前接口1033,获取会员折扣价
	 * 
	 * @param mid
	 * @param cardNo
	 * @param productId
	 * @throws Exception
	 */
	public Map<String, Integer> priceByRule(String mid, String cardNo, String productId) {
		JSONObject param = new JSONObject();
		param.put("mid", mid); // 慧商户号
		param.put("cardNo", cardNo); // 会员卡号
		param.put("productId", productId); // 商品id，多个商品用","分开拼成一个字符串
		
		JSONObject json = new JSONObject();
		json.put("param", param);
		json.put("service_code", "1033");
		
		JSONObject resJson = null;
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		}
		
		Map<String, Integer> priceMap = new HashMap<String, Integer>(); 
		if (resJson == null || !resJson.containsKey("code") || !"0".equals(resJson.get("code"))) {
			return null;
		}
		
		JSONArray memberPrice = resJson.getJSONObject("result").getJSONArray("memberPrice");
		if (memberPrice == null || memberPrice.isEmpty()) {
			return null;
		}
		
		for (int i = 0; i < memberPrice.size(); i++) {
			String str = memberPrice.get(i).toString();
			if (!str.contains("|")) {
				continue;
			}
			String[] arr = str.split("|");
			priceMap.put(arr[0], Integer.parseInt(arr[1]));
		}
		
		return priceMap;
	}
	
	/**
	 * 获取可用的餐桌列表
	 * 
	 * @param mid
	 * 			慧商户号
	 * @param date
	 * 			日期
	 * @param timeId
	 * 			时段Id
	 * @return
	 */
	public JSONArray getUnUsedErpTable(String mid, String date, String timeId) {
		JSONObject param = new JSONObject();
		param.put("mid", mid); // 慧商户号
		param.put("date", date); // 日期
		param.put("timeId", timeId); // 时段Id
		
		JSONObject response = null;
		try {
			response = postOpen("/catering/table/unused", param);
		} catch (Exception e) {
			log.error(e.getMessage());
			return null;
		}
		
		if (!response.containsKey("code") || !"0".equals(response.get("code"))) {
			log.error(response.get("message"));
			return null;
		}
		
		JSONArray result = response.getJSONArray("result");
		if (result == null || result.isEmpty()) {
			return null;
		}
		
		return result;
	}
	
	public boolean isTableUsing(String mid, String tableId) {
		JSONObject param = new JSONObject();
		param.put("mid", mid); // 慧商户号
		param.put("tableId", tableId); // 时段Id
		
		JSONObject response = null;
		try {
			response = postOpen("/catering/table/using", param);
		} catch (Exception e) {
			log.error(e.getMessage());
			return false;
		}
		
		if (!response.containsKey("code") || !"0".equals(response.get("code"))) {
			log.error(response.get("message"));
			return false;
		}
		
		JSONObject result = response.getJSONObject("result");
		if (result == null || result.isEmpty()) {
			return false;
		}
		
		return result.getBoolean("using");
	}
	
	/**
	 * 获取用户可用商户代金券
	 * 
	 * @param mid
	 * @return
	 */
	public JSONObject getCashTickets(String openId, String mid, String cardId) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		param.put("openId", openId);// mid慧商户号
		param.put("cardId", cardId);//会员卡ID
		
		JSONObject json = new JSONObject();
		json.put("service_code", "1039");
		json.put("param", param);

		JSONObject resJson = new JSONObject();
		try {
			// 调用会员易对外接口查询是否存在微信会员卡
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("获取用户可用商户代金券请求出错");
		}

		return resJson;
	}
	
	/**
	 * 获取用户支付可用券（代金券、折扣券）
	 * 
	 * @param mid
	 * @param cardId
	 * @return
	 */
	public List<TicketInfoPayUse> getPayUseTickets(String mid, String cardId) {
		TicketPayUseInput input = new TicketPayUseInput();
		input.setMid(mid);
		input.setCardId(cardId);
		TicketPayUseOutput output = (TicketPayUseOutput) wizarposOpenRestClient.post(input,"/wechart/ticket_pay_use",TicketPayUseOutput.class);
		if (output == null || !SysConstants.OPEN_SUCCESS.equals(output.getCode())) {
			if (output == null) {
				log.error("请求开放平台查询用户支付可用券集合接口失败");
			} else {
				log.error("code: " + output.getCode());
				log.error("message: " + output.getMessage());
			}
			return null;
		}

		return output.getResult().getTicketList();
	}
	
	/**
	 * 获取第三方会员折扣
	 * 
	 * @param mid
	 * @return
	 */
	public JSONObject getThirdDiscount(String openId, String mid) {
		// TODO
		return null;
	}
	
	/**
	 * 取自定义微信券号,W打头
	 * 
	 * @param mid
	 * @return
	 */
	public String getTicketCode(String mid) {
		JSONObject param = new JSONObject();
		param.put("mid", mid);// mid慧商户号
		JSONObject json = new JSONObject();
		json.put("service_code", "1017");
		json.put("param", param);
		JSONObject resJson = null;
		
		try {
			resJson = postMember(json);
		} catch (Exception e) {
			throw new RuntimeException("生成券号出错");
		}
		
		String ticketInfoId = null;
		if (resJson != null && resJson.containsKey("code") 
				&& 0==resJson.getIntValue("code")) {
			ticketInfoId = resJson.getJSONObject("result")
					.getString("ticketInfoId");
		}
		
		if (ticketInfoId == null) {
			throw new RuntimeException("生成自定义微信券号出错");
		}
	
		return ticketInfoId;
	}
	
	/**
	 * 推送管家号下单模板消息
	 * 
	 * @param mid
	 * @param orderId
	 * @param tranLogId
	 * @param msgType
	 */
	public void pushHouseKeeperOrderSubmitMsg(String mid, String orderId) {
		pushHouseKeeperMsg(mid, orderId, "", MsgType.OrderSubmit.getName());
	}

	/**
	 * 推送管家号收款模板消息
	 * 
	 * @param mid
	 * @param orderId
	 * @param tranLogId
	 * @param msgType
	 */
	public void pushHouseKeeperPaymentMsg(String mid, String tranLogId) {
		pushHouseKeeperMsg(mid, "", tranLogId, MsgType.Pament.getName());
	}
	
	/**
	 * 推送管家号模板消息
	 * 
	 * @param mid
	 * @param orderId
	 * @param tranLogId
	 * @param msgType
	 */
	private void pushHouseKeeperMsg(String mid, String orderId, String tranLogId, String msgType) {
		// 推送管家号消息提醒
		TemplatePushOnlineInput templatePushOnlineInput = new TemplatePushOnlineInput();
		templatePushOnlineInput.setMid(mid);
		templatePushOnlineInput.setOrderId(orderId);
		templatePushOnlineInput.setTranLogId(tranLogId);
		// 模板消息类型(短信充值通知SMS_CHARGE,短信余额通知SMS_BALANCE,收款通知PAYMENT,退款通知REFUND,下单提醒ORDER_SUBMIT,订单取消ORDER_CANCEL)
		templatePushOnlineInput.setMsgType(msgType);
		wizarposOpenRestClient.post(templatePushOnlineInput, "/template/push/online", TemplatePushOnlineOutput.class);			
	}
	
	/**
	 * 请求微信 jsapi_ticket 签名（部分jssdk调用凭证）
	 * 
	 * @param mid
	 * @param url
	 * @return
	 */
	public Map<String, String> weixinJsApiTicketConfig(String mid, String url) {
		Map<String, String> result = getWeixinJsApiTicket(mid);
		if (result != null) {
			String jsTicket = result.get("ticket");
			result.put("appId", result.get("appid"));
			Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
					WxSignUtil.createTimestamp());
			result.putAll(ret);
			return result;
		} 
		return null;
	}
	
	/**
	 * 请求微信 jsapi_ticket
	 * 
	 * @param mid
	 * @return
	 */
	private Map<String, String> getWeixinJsApiTicket(String mid) {
		// 请求微信jsapi_ticket
		AccessTokenInput jsInput = new AccessTokenInput();
		jsInput.setMid(mid);
		CommonResultOutput jsOutput = (CommonResultOutput) wizarposOpenRestClient.post(jsInput, "/weixin/ticket/js", CommonResultOutput.class);
		if (jsOutput != null && SysConstants.OPEN_SUCCESS.equals(jsOutput.getCode())) {// 请求开放平台出错
			return (Map<String, String>) jsOutput.getResult();
		} else {
			log.error("请求开放平台获取微信js api的ticket接口");
			if (jsOutput != null) {
				log.error("code：" + jsOutput.getCode());
				log.error("message：" + jsOutput.getMessage());
			}
		}
		return null;
	}
	
	/**
	 * 请求微信 access_token
	 * 
	 * @param mid
	 * @return
	 */
	public String weixinAccessToken(String mid) {
		// 请求微信jsapi_ticket
		AccessTokenInput accessTokenInput = new AccessTokenInput();
		accessTokenInput.setMid(mid);
		AccessTokenOutput accessOutput = (AccessTokenOutput) wizarposOpenRestClient.post(accessTokenInput, "/weixin/accesstoken", AccessTokenOutput.class);
		if (accessOutput != null && SysConstants.OPEN_SUCCESS.equals(accessOutput.getCode())) {// 请求开放平台出错
			return accessOutput.getResult().getToken();
		} else {
			log.error("请求开放平台获取微信js api的ticket接口");
			if (accessOutput != null) {
				log.error("code：" + accessOutput.getCode());
				log.error("message：" + accessOutput.getMessage());
			}
		}
		return null;
	}
	
	/**
	 * 请求微信 jsapi_ticket （地理位置用） 签名（部分jssdk调用凭证）
	 * 
	 * @param mid
	 * @param url
	 * @return
	 */
	public Map<String, String> weixinJsApiTicketConfigForLocation(String mid, String url) {
		Map<String, String> result = getWeixinJsApiTicket(mid);
		if (result != null) {
			String jsTicket = result.get("ticket");
			result.put("appId", result.get("appid"));
			Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
					WxSignUtil.createTimestamp());
			String accessToken = weixinAccessToken(mid);
			if (!StringUtils.isEmpty(accessToken)) {
				result.putAll(ret);
				String retLoc = WxSignUtil.signLocation(accessToken, result.get("appId"), url,
						ret.get("timestamp"), ret.get("noncestr"));
				result.put("addrSign", retLoc);
				return result;
			}
		} 
		return null;
	}
}
